//{==================================================================================================
//! @file SqrDivider.cpp
//! @date 2013-09-29
//! @mainpage Program for establishing the existence of at least one closure \
              of the set of divisors of N for the function x^ 2
//! @author Kirill Shcherbatov <kshcherbatov@gmail.com>, 376 group, DCAM MIPT
//! @version 1.0
//! @note Task B, varriant 1, test 2007, MIPT
//}===================================================================================================

//****************************************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
//****************************************************************************************************

//****************************************************************************************************
#define _EJC
#define PARANOIC_MODE
//****************************************************************************************************

//****************************************************************************************************
//! @def   OUT
//! @note  -Use OUT to print your text in console. It is checking _EJC declaration.
//! @note  -Only if _EJC is defined then the program prints your text.
//! @note  --You also can define _EJC in compilation command (g++ main.cpp -D _EJC)
//----------------------------------------------------------------------------------------------------
#ifdef _EJC
    #define OUT printf
#else
    #define OUT if (0) printf
#endif // _EJC
//****************************************************************************************************


//****************************************************************************************************
//! @def    VALID
//! @param  CONDITIONAL for checking
//! @param  MESSAGE for displaying if CONDITIONAL is false
//! @note   -It checks the validity of the expression.
//! @note   -Program will use OUT to display MESSAGE
//! @note   -If sended conditional is false, program will be terminated sending 1 message
//----------------------------------------------------------------------------------------------------
#ifdef  PARANOIC_MODE
    #define VALID( CONDITIONAL, MESSAGE )       \
    if (!(CONDITIONAL))                         \
    {                                           \
        OUT  ( MESSAGE );                       \
        exit ( 1 );                             \
    } // VALID in PARANOIC_MODE
#else
    #define VALID( CONDITIONAL, MESSAGE ) \
    CONDITIONAL;
#endif
//****************************************************************************************************

//****************************************************************************************************
//! @def    CHECK
//! @param  CONDITIONAL for checking
//! @param  MESSAGE for displaying if CONDITIONAL is false
//! @note   -It checks the validity of the expression.
//! @note   -Program will use OUT to display MESSAGE
//! @note   -If sended conditional is false, program will be terminated sending 1 message
//! @warning   IN RELIASE MODE IT WILL BE REMOOVED
//----------------------------------------------------------------------------------------------------
#ifdef PARANOIC_MODE
    #define CHECK( CONDITIONAL, MESSAGE )       \
    if (!(CONDITIONAL))                         \
    {                                           \
        OUT  ( MESSAGE );                       \
        exit ( 1 );                             \
    } // CHECK in PARANOIC_MODE
#else
    #define CHECK( CONDITIONAL, MESSAGE )
#endif
//****************************************************************************************************

//****************************************************************************************************
inline long long unsigned int SearchSqrDivider(register unsigned long long int N);
//****************************************************************************************************

//****************************************************************************************************
//! @param - number of sending arguments
//! @param argv[] - arguments, include generated by OS
//! @return 0 on success
//----------------------------------------------------------------------------------------------------
int main(int, const char* argv[])
{
    OUT ("%s (%s) %s %s:\n\n", argv[0], __FILE__, __DATE__, __TIME__);
    OUT ("#Program for establishing the existence of at \n"
         "  #one closure of the set of divisors of N for the function x^ 2\n\n");

    OUT ("#Enter N, the number for researching\n");
    OUT ("#N=");

    unsigned long long int N=0;

    VALID (scanf ("%u", &N) == 1,  "#Problems with inputed N. Read the instructions above & try again.\n");

    const long long unsigned int N_MAX = 1llu << 31;

    CHECK (N >= 0, "#Inputed N is incorrect. N should be greater than 0.\n");
    CHECK (N < N_MAX, "#Inputed N is incorrect. N should be lower than 10 000.\n");

    long long unsigned int result = SearchSqrDivider(N);

    OUT ("#OK, the answer is ");

    if (result)
    {
        printf("YES\n");
        OUT("Exist the dividers %llu & %llu | %llu^2=%llu\n", result, result*result, result, result*result);
    } else printf("NO\n");

    return 0;
}
//****************************************************************************************************

//****************************************************************************************************
//! @param N number for research
//! @return 0 on success
//----------------------------------------------------------------------------------------------------
inline long long unsigned int SearchSqrDivider(register unsigned long long int N)
{
    unsigned long long int sqrt_n=sqrt(N) + 1;
    for (register unsigned long long int i = 2; i < sqrt_n; i++) //+1 just in case
        if ( !(N % i) && !(N % (i*i)) ) return i;
    return 0;
}
//****************************************************************************************************
